#pragma once
#include <iostream>
#include <queue>
#include <vector>



#include "MyMutex.hpp"
#include "CondVal.hpp"
#include "Task.hpp"
#include "Log.hpp"



static const int gcap = 10;

namespace BlockQueueArea
{
    using namespace CondValArea;
    using namespace MyMutexArea;

    template<class T>
    class MyBlockQueue
    {
    private:
        bool IsFull()
        {
            return _qu.size()==_cap;
        }

        bool IsEmpty()
        {
            return _qu.empty();
        }
    public:
        MyBlockQueue(int cap = gcap):_cap(cap),_producer_wait(0),_consumer_wait(0)
        {}

        void Push(const T& data)//生产
        { 
            LockGuard lockguard(_mutex);
            // _mutex.Lock();//加锁
            while(IsFull())//队列满了，让消费者拿，生产者等待
            {
                printf("生产者进入等待...\n");
                _producer_wait++;
                _producer_cond.PthreadWait(_mutex);
                _producer_wait--;
                printf("生产者被唤醒...\n");
            }
            _qu.push(data);
            std::cout<<"生产了一个数据"<<std::endl;

            if(_consumer_wait)//生产数据后,如果有消费者在等待,唤醒消费者线程
                _consumer_cond.PthreadSignal();
            
            // _mutex.UnLock();//解锁
        }

        void Pop(T* pop)//消费
        {
            //_mutex自动加锁解锁(构造、析构)
            LockGuard lockguard (_mutex);
            // _mutex.Lock();//加锁
            while(IsEmpty())//队列为空，让生产者生产，消费者等待
            {
                printf("消费者进入等待...\n");
                _consumer_wait++;
                _consumer_cond.PthreadWait(_mutex);//等待
                _consumer_wait--;
                printf("消费者被唤醒...\n");
            }
            std::cout<<"消费了一个数据"<<std::endl;
            *pop = _qu.front();
            _qu.pop();

            if(_producer_wait)//消费数据后,如果有生产者等待,唤醒生产者线程
                _producer_cond.PthreadSignal();

            // _mutex.UnLock();//解锁
        }


        ~MyBlockQueue()
        {}

    private:
        std::queue<T> _qu;//存储数据的底层容器
        MyMutex _mutex;//锁
        MyCondVal _producer_cond;//给生产者提供的条件变量
        MyCondVal _consumer_cond;//给消费者提供的条件变量
        int _cap;//队列最大容量
        int _producer_wait;//等待的生产线程数量
        int _consumer_wait;//等待的消费线程数量

    };
}